//Name: Cao Dung Anh
//Class: 11CTT
//Sid: 1151003

#include <iostream>
using namespace std;
#include <string>
#include "BookInfo.h"
#include "BookList.h"
#include <fstream>


BookList::BookList()
{
	head = NULL;
	subhead = NULL;
	loadBooks();
}

void BookList::addBooktoList()
{
	BookInfo temp;
	temp.addBook();

	ofstream file;
	file.open("BookInfo.bin",ios::binary | ios::ate | ios::app);
	
	file.write((char*)&temp,sizeof(temp));

	file.close();
}

void BookList::addBooktoList(char *ISBN)
{
	BookInfo temp;
	temp.addBook(ISBN);

	ofstream file;
	file.open("BookInfo.bin",ios::binary | ios::ate | ios::app);

	file.write((char*)&temp,sizeof(temp));

	file.close();

	cout << "Book added successfully\n";
}

void BookList::updateBookList()
{
	BookInfo temp;

	Node *cur = head;
	ofstream file;
	file.open("BookInfo.bin",ios::binary);

	while (cur)
	{
		temp.copyBook(cur->data);
		file.write((char*)&temp,sizeof(temp));
		cur = cur->next;
	}

	file.close();
	cout << "Update successfully\n";
}


void BookList::loadBooks()
{
	if (head != NULL)
	{
		freeHead();
	}
	Node *cur = head;
	BookInfo buffer;
	ifstream file;
	file.open("BookInfo.bin",ios::binary);

	while (file.read((char*)&buffer,sizeof(buffer)))
	{
		Node *newNode = new Node;
		newNode->data.copyBook(buffer);
		newNode->next = NULL;
		if (head == NULL)
		{
			head = newNode;
		}
		else
		{
			cur = head;
			while(cur->next)
			{
				cur = cur->next;
			}
			cur->next = newNode;
		}
	}

	file.close();
}

//Create a sub Linked list
void BookList::addNodetoSubList(Node *cur)
{
	Node *subcur;
	Node *newNode = new Node;
	newNode->data.copyBook(cur->data);
	newNode->next = NULL;
	if (subhead == NULL)
	{
		subhead = newNode;
	}
	else
	{
		subcur = subhead;
		while (subcur->next)
		{
			subcur = subcur->next;
		}
		subcur->next = newNode;
	}
}

//Free subhead
void BookList::freeSubhead()
{
	Node* cur = subhead;
	while (subhead)
	{
		subhead = subhead->next;
		delete cur;
		cur = subhead;
	}
}
//Free Head
void BookList::freeHead()
{
	Node* cur = head;
	while (head)
	{
		head = head->next;
		delete cur;
		cur = head;
	}
}


bool BookList::showAllBook()
{
	freeSubhead();
	int count = 0;
	Node *cur = head;
	while(cur)
	{
		++count;
		cout << endl;
		cur->data.showBook();
		addNodetoSubList(cur);
		cout << "------------------------------------------------\n";
		cur = cur->next;
	}
	if (count == 0)
	{
		return false;
	}
	return true;
}

//Show books in the sublist (the sorted/filtered list)
void BookList::showSubList()
{
	Node *cur = subhead;
	while(cur)
	{
		cout << endl;
		cur->data.showBook();
		cout << "------------------------------------------------\n";
		cur = cur->next;
	}
}

//Find stock of a book base on it's ISBN
int BookList::inStock(char *ISBN)
{
	Node *cur = head;
	while (cur)
	{
		if (strcmp(cur->data.getISBN(),ISBN)==0)
		{
			return cur->data.getStock();
		}
		cur = cur->next;
	}
	cout << "ISBN does not match, some errors have occur\n";
	return 0;
}

//Filter by name of the book
bool BookList::filterbyName()
{
	freeSubhead();
	int count = 0; //count the number of book require
	char name[100];
	cout << "Enter the Book's name: ";
	cin.getline(name,sizeof(name));

	Node *cur = head;
	while (cur)
	{
		if (strstr(cur->data.getName(),name) != NULL)
		{
			++count;
			cout << endl;
			cur->data.showBook();
			cout << "------------------------------------------------\n";
			addNodetoSubList(cur);
		}
		cur=cur->next;
	}
	if (count == 0)
	{
		return false;
	}
	return true;
}

//Filter by type of Book
bool BookList::filterbyType()
{
	freeSubhead();
	int count = 0; //count the number of book require
	char type[100];
	cout << "Enter type of your book: ";
	cin.getline(type,sizeof(type));

	Node *cur = head;
	while(cur)
	{
		if (strstr(cur->data.getType(),type) != NULL)
		{
			++count;
			cout << endl;
			cur->data.showBook();
			cout << "------------------------------------------------\n";
			addNodetoSubList(cur);
		}
		cur=cur->next;
	}
	
	if (count == 0)
	{
		return false;
	}
	return true;
}

//Filter by ISBN
bool BookList::filterbyISBN()
{
	freeSubhead();
	int count = 0;
	char ISBN[14];
	cout << "Enter ISBN: ";
	cin.getline(ISBN,sizeof(ISBN));

	Node *cur = head;
	Node *subcur = subhead;
	while (cur)
	{
		if (strstr(cur->data.getISBN(),ISBN) != NULL)
		{
			++count;
			cout << endl;
			cur->data.showBook();
			cout << "------------------------------------------------\n";
			addNodetoSubList(cur);
		}
		cur = cur->next;
	}

	if (count == 0)
	{
		return false;
	}
	return true;
}

//Filter by Number of books
bool BookList::filterbyStock()
{
	freeSubhead();
	int count = 0;
	int stock;
	cout << "Enter Number of books: ";
	cin >> stock;

	Node *cur = head;
	while (cur)
	{
		if (cur->data.getStock() == stock)
		{
			++count;
			cout << endl;
			cur->data.showBook();
			cout << "------------------------------------------------\n";
			addNodetoSubList(cur);
		}
		cur = cur->next;
	}
	cin.get();// Delete some buffer here
	if (count == 0)
	{
		return false;
	}
	return true;
}

//Filter by Year of publication
bool BookList::filterbyYoP()
{
	freeSubhead();
	int count = 0;
	int YoP;
	cout << "Enter Year of Publication: ";
	cin >> YoP;

	Node *cur = head;
	while (cur)
	{
		if (cur->data.getYoP() == YoP)
		{
			++count;
			cout << endl;
			cur->data.showBook();
			cout << "------------------------------------------------\n";
			addNodetoSubList(cur);
		}
		cur = cur->next;
	}

	if (count == 0)
	{
		return false;
	}
	return true;
}

//Insert a new book
void BookList::insertBook()
{
	int c=2;
	bool stop;
	do 
	{
		stop = false;
		char ISBN[14];
		cout << "Enter ISBN: ";
		cin.getline(ISBN,sizeof(ISBN));

		cout << "Searching...";
		Node *cur = head;
		while (cur && stop == false)
		{
			if (strcmp(cur->data.getISBN(),ISBN) == 0)
			{
				cur->data.showBook();
				// if update stock(cur) == true then it will terminate the function and return to main menu
				if(updateStock(cur) == true)
				{
					cin.get();
					return;
				}
				stop = true;
				break;
			}
			cur = cur->next;
		}

		if (stop == false)
		{
			cout << "This book has not been in the database\n"
				<< "Please add more information for this book:\n";
			addBooktoList(ISBN);
			loadBooks();
		}
		cout << "1. Insert another book\n"
			<< "2. Return to main menu\n";
		cout << "Choose...";
		cin >> c;
		cin.get();
	} while ( c != 2);
	return;
}

bool BookList::updateStock(Node *cur)
{
	int c;
	cout << "1. Update the number of book\n"
		 << "2. Back\n"
		 << "3. Return to the main menu\n";
	do 
	{
		cout << "Choose ";
		cin >> c;
		switch(c)
		{
		case 1:
			int n;
			do 
			{
				cout << "The new number of book: ";
				cin >> n;
				if (n < 0)
				{
					cout << "The minimum number of book is 0\n"
						<< "Please insert again\n";
				}
			} while (n < 0);
			cur->data.setStock(n);
			updateBookList();
			return false;
		case 2:
			return false;
		case 3:
			return true;
		default:
			cout << "Invalid option, you have to choose again\n";
			break;
		}
	} while (c != 1 && c != 2 && c != 3);
	cin.get();
	
}

//Sort by year of publication (Ascending)
void BookList::SortbyYoPAscending()
{
	Node* cur = subhead;
	int smallest = subhead->data.getYoP();
	Node* temp;
	while(cur->next)
	{
		if(cur->next->data.getYoP()<smallest)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			smallest = subhead->data.getYoP();
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		smallest = cur->next->data.getYoP();
		temp= cur->next;
		while(temp->next)
		{
			if(temp->next->data.getYoP()<smallest)
			{
				smallest = temp->next->data.getYoP();
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by year of publication (Descending)
void BookList::SortbyYoPDescending()
{
	Node* cur = subhead;
	int biggest = subhead->data.getYoP();
	Node* temp;
	while(cur->next)
	{
		if(cur->next->data.getYoP()>biggest)
		{

			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			biggest = subhead->data.getYoP();
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		biggest = cur->next->data.getYoP();
		temp= cur->next;
		while(temp->next)
		{
			if(temp->next->data.getYoP()>biggest)
			{

				biggest = temp->next->data.getYoP();
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by stock (Ascending)
void BookList::SortbyStockAscending()
{
	Node* cur = subhead;
	int smallest = subhead->data.getStock();
	Node* temp;
	while(cur->next)
	{
		if(cur->next->data.getStock()<smallest)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			smallest = subhead->data.getStock();
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		smallest = cur->next->data.getStock();
		temp= cur->next;
		while(temp->next)
		{
			if(temp->next->data.getStock()<smallest)
			{
				smallest = temp->next->data.getStock();
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by stock (Descending)
void BookList::SortbyStockDescending()
{
	Node* cur = subhead;
	int biggest = subhead->data.getStock();
	Node* temp;
	while(cur->next)
	{
		if(cur->next->data.getStock()>biggest)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			biggest = subhead->data.getStock();
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		biggest = cur->next->data.getStock();
		temp= cur->next;
		while(temp->next)
		{
			if(temp->next->data.getStock()>biggest)
			{
				biggest = temp->next->data.getStock();
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by Name (Ascending)
void BookList::SortbyNameAscending()
{
	Node* cur = subhead;
	char smallest[100];
	strcpy(smallest,subhead->data.getName());
	Node* temp;
	while(cur->next)
	{
		if(strcmp(smallest,cur->next->data.getName())>0)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			strcpy(smallest,subhead->data.getName());
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		strcpy(smallest,cur->next->data.getName());
		temp= cur->next;
		while(temp->next)
		{
			if(strcmp(smallest,temp->next->data.getName())>0)
			{
				strcpy(smallest,temp->next->data.getName());
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by Name (Descending)
void BookList::SortbyNameDescending()
{
	Node* cur = subhead;
	char biggest[100];
	strcpy(biggest,subhead->data.getName());
	Node* temp;
	while(cur->next)
	{
		if(strcmp(biggest,cur->next->data.getName())<0)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			strcpy(biggest,subhead->data.getName());
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		strcpy(biggest,cur->next->data.getName());
		temp= cur->next;
		while(temp->next)
		{
			if(strcmp(biggest,temp->next->data.getName())<0)
			{
				strcpy(biggest,temp->next->data.getName());
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by Type (Ascending)
void BookList::SortbyTypeAscending()
{
	Node* cur = subhead;
	char smallest[100];
	strcpy(smallest,subhead->data.getType());
	Node* temp;
	while(cur->next)
	{
		if(strcmp(smallest,cur->next->data.getType())>0)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			strcpy(smallest,subhead->data.getType());
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		strcpy(smallest,cur->next->data.getType());
		temp= cur->next;
		while(temp->next)
		{
			if(strcmp(smallest,temp->next->data.getType())>0)
			{
				strcpy(smallest,temp->next->data.getType());
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by Type (Descending)
void BookList::SortbyTypeDescending()
{
	Node* cur = subhead;
	char biggest[100];
	strcpy(biggest,subhead->data.getType());
	Node* temp;
	while(cur->next)
	{
		if(strcmp(biggest,cur->next->data.getType())<0)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			strcpy(biggest,subhead->data.getType());
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		strcpy(biggest,cur->next->data.getType());
		temp= cur->next;
		while(temp->next)
		{
			if(strcmp(biggest,temp->next->data.getType())<0)
			{
				strcpy(biggest,temp->next->data.getType());
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by ISBN (Ascending)
void BookList::SortbyISBNAscending()
{
	Node* cur = subhead;
	char smallest[100];
	strcpy(smallest,subhead->data.getISBN());
	Node* temp;
	while(cur->next)
	{
		if(strcmp(smallest,cur->next->data.getISBN())>0)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			strcpy(smallest,subhead->data.getISBN());
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		strcpy(smallest,cur->next->data.getISBN());
		temp= cur->next;
		while(temp->next)
		{
			if(strcmp(smallest,temp->next->data.getISBN())>0)
			{
				strcpy(smallest,temp->next->data.getISBN());
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

//Sort by ISBN (descending)
void BookList::SortbyISBNDescending()
{
	Node* cur = subhead;
	char biggest[100];
	strcpy(biggest,subhead->data.getISBN());
	Node* temp;
	while(cur->next)
	{
		if(strcmp(biggest,cur->next->data.getISBN())<0)
		{
			temp = cur->next;
			cur->next = temp->next;
			temp->next = subhead;
			subhead = temp;
			strcpy(biggest,subhead->data.getType());
		}
		else
			cur = cur->next;
	}

	cur = subhead;
	while(cur->next)
	{
		strcpy(biggest,cur->next->data.getISBN());
		temp= cur->next;
		while(temp->next)
		{
			if(strcmp(biggest,temp->next->data.getISBN())<0)
			{
				strcpy(biggest,temp->next->data.getISBN());
				Node* TEMP;
				TEMP = temp->next;
				temp->next = TEMP->next;
				TEMP->next = cur->next;
				cur->next = TEMP;
			}
			else
				temp = temp->next;
		}
		cur = cur->next;
	}
}

void BookList::decreaseStock( char *ISBN )
{
	Node *cur = head;

	while (cur)
	{
		if (strcmp(cur->data.getISBN(),ISBN) == 0)
		{
			cur->data.setStock(cur->data.getStock() - 1);
			updateBookList();
			loadBooks();
			return;
		}
		cur = cur->next;
	}
	cout << "ISBN does not match, some errors have occur\n";
	return;
}

char * BookList::getNamebyISBN( char* ISBN )
{
	Node *cur = head;

	while (cur)
	{
		if (strcmp(cur->data.getISBN(),ISBN) == 0)
		{
			return cur->data.getName();
		}
		cur = cur->next;
	}
	cout << "ISBN does not match, some errors have occur\n";
	return NULL;
}

bool BookList::isExist(char *ISBN)
{
	Node* cur = head;
	while (cur)
	{
		if (strcmp(cur->data.getISBN(),ISBN) == 0)
		{
			return true;
		}
		cur = cur->next;
	}
	return false;
}

//Show a book
void BookList::showBook(char *ISBN)
{
	Node* cur = head;
	while (cur)
	{
		if (strcmp(cur->data.getISBN(),ISBN) == 0)
		{
			cur->data.showBook();
			return;
		}
		cur = cur->next;
	}
}

//Save info to XML file
void BookList::WriteBookInfoXMLfile()
{
	Node *cur = subhead;
	char name[100];
	cout << "File name(Ex: save):";
	cin.getline(name,100);
	strcat(name,".xml");
	ofstream file;
	file.open(name,ios::out);
	if (file.good()==false)
		return ;
	file <<"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"<<endl;
	file << "<Book>" << endl;
	while(cur)
	{
		file << "\t<BookInfo>"<<endl;
		file << "\t\t<ISBN>"<<cur->data.getISBN()<<"</ISBN>"<<endl;
		file << "\t\t<Name>"<<cur->data.getName()<<"</Name>"<<endl;
		file << "\t\t<Kind>"<<cur->data.getType()<<"</Kind>"<<endl;
		file << "\t\t<NameofAuthor>"<<cur->data.getAuthorName()<<"</NameofAuthor>"<<endl;
		file << "\t\t<Publisher>"<<cur->data.getPublisher()<<"</Publisher>"<<endl;
		file << "\t\t<Yearofpublication>"<<cur->data.getYoP()<<"</Yearofpublication>"<<endl;
		file << "\t\t<Stock>"<<cur->data.getStock()<<"</Stock>"<<endl;
		file << "\t</BookInfo>"<<endl;
		cur = cur->next;
	}
	file << "</Book>" << endl;
	file.close();
}

//Save info to a CSV file
void BookList::WriteBookInfoCSVfile()
{
	Node *cur = subhead;
	char name[100];
	cout << "File name(Ex: save):";
	cin.getline(name,100);
	strcat(name,".csv");
	ofstream file;
	file.open(name,ios::out);
	if (file.good()==false)
		return ;

	file << "ISBN,";
	file << "Name,";
	file << "Kind,";
	file << "Name of Author,";
	file << "Publisher,";
	file << "Year of publication,";
	file << "Stock"<< endl;


	while(cur)
	{
		file << cur->data.getISBN()<<",";
		file << cur->data.getName()<<",";
		file << cur->data.getType()<<",";
		file << cur->data.getAuthorName()<<",";
		file << cur->data.getPublisher()<<",";
		file << cur->data.getYoP()<<",";
		file << cur->data.getStock()<<endl;
		cur = cur->next;
	}
	file.close();
}


